#include "game.h"
#include "snake.h"
#include "tty.h"
#include "point.h"
#include "networking.h"
#include "graphics.h"
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>

Point objFoodPoint;
SnakeCollection *objSnakeCollection;
char cNextSnakeChar;
int iSelfServerPort;
int iUDPSendingFD;
int iFirstPortNumber;
int iMaxPlayers;

void processMessage(char *sMessage, int iMessageLength, struct sockaddr_in objRemoteAddress)
{
	SnakeCollection *thruSnakeCollection = objSnakeCollection;
	Snake *ptrRemoteSnake;
	int iBytesConsumed = 0, iRemotePort;

	if (iMessageLength < 5)
		return;

	iRemotePort = *((int*)&sMessage[0]);
	sMessage += 4;

	while (thruSnakeCollection != NULL)
	{
		if (thruSnakeCollection->ptrRemoteSocketAddress != NULL) // skip self
		{
			if (iRemotePort == thruSnakeCollection->iRemotePort)
			{
				ptrRemoteSnake = thruSnakeCollection->ptrSnake;
				break;
			}
		}

		thruSnakeCollection = thruSnakeCollection->ptrNext;
	}

	if (thruSnakeCollection == NULL)
	{
		SnakeCollection *ptrNewCollectionElement = malloc(sizeof(SnakeCollection));;

		thruSnakeCollection = objSnakeCollection;
		
		while (thruSnakeCollection->ptrNext != NULL)
			thruSnakeCollection = thruSnakeCollection->ptrNext;

		ptrRemoteSnake = initSnake(makePoint(1, 1), getNextSnakeChar());
		ptrNewCollectionElement->ptrSnake = ptrRemoteSnake;
		ptrNewCollectionElement->ptrNext = NULL;
		ptrNewCollectionElement->ptrRemoteSocketAddress = &objRemoteAddress;
		ptrNewCollectionElement->iRemotePort = iRemotePort;
		
		thruSnakeCollection->ptrNext = ptrNewCollectionElement;
	}

	if (sMessage[0] == 0x01)
	{
		int iSnakeLength = *((int*)&sMessage[1]);

		if (getSnakeLength(ptrRemoteSnake) > iSnakeLength)
			removeOneSnakePiece(ptrRemoteSnake);
		iBytesConsumed += 5;
	}
	else if (sMessage[0] == 0x02)
	{
		addOneSnakePiece(ptrRemoteSnake, makePoint((int)sMessage[1], (int)sMessage[2]));
		iBytesConsumed += 3;
	}
	else if (sMessage[0] == 0x03)
	{
		objFoodPoint = makePoint((int)sMessage[1], (int)sMessage[2]);
		drawFood();
		iBytesConsumed += 3;
	}

	if (iMessageLength - iBytesConsumed > 0)
		processMessage(sMessage + iBytesConsumed, iMessageLength - iBytesConsumed, objRemoteAddress);
}

void* threadForInput(void *vptrMySnake)
{
	char c;
	Snake *ptrMySnake = (Snake*)vptrMySnake;

	if (tty_break() != 0)
	{
		printf("Error: We were unable to get control of stdin. Make sure you're using csil-core machines.");
		exit(1);
	}

	do
	{
		c = tty_getchar();

		switch (c)
		{
			case 65:
				if (ptrMySnake->ePreviousDirectionMoved != SOUTH)
					ptrMySnake->eCurrentDirection = NORTH;
				break;

			case 66:
				if (ptrMySnake->ePreviousDirectionMoved != NORTH)
					ptrMySnake->eCurrentDirection = SOUTH;
				break;

			case 67:
				if (ptrMySnake->ePreviousDirectionMoved != WEST)
					ptrMySnake->eCurrentDirection = EAST;
				break;

			case 68:
				if (ptrMySnake->ePreviousDirectionMoved != EAST)
					ptrMySnake->eCurrentDirection = WEST;
				break;
		}
	} while (c != 'q');

	tty_fix();
	gotoxy(0, 24);
	exit(0);
}

int main(int argc, char **argv)
{
	if (argc != 4)
	{
		printf("Usage: %s <first port number> <my player ID (eg: 1, 2)> <number of players>\n", argv[0]);
		return 1;
	}

	printf("Starting up UIUC Snake...\n");

	cNextSnakeChar = '1';
	pthread_t objInputThread, objUDPServerThread;
	iFirstPortNumber = atoi(argv[1]);
	iSelfServerPort = atoi(argv[2]) + iFirstPortNumber - 1;
	iMaxPlayers = atoi(argv[3]);

	objSnakeCollection = malloc(sizeof(SnakeCollection));

	Snake *ptrMySnake = initSnake(makePoint(40, 10), getNextSnakeChar());
	objSnakeCollection->ptrSnake = ptrMySnake;
	objSnakeCollection->ptrNext = NULL;
	objSnakeCollection->ptrRemoteSocketAddress = NULL;
	printf("* Created local snake.\n");

	createUDPSendingSocket();
	printf("* Created socket for outgoing messages.\n");

	pthread_create(&objInputThread, NULL, threadForInput, ptrMySnake);
	printf("* Launched user I/O thread.\n");

	pthread_create(&objUDPServerThread, NULL, UDPServerThread, &iSelfServerPort);
	printf("* Launched thread to listen on UDP/%d.\n", iSelfServerPort);

	printf("Done! Switching to graphical mode.\n");

	drawBorder();
	placeNewFood();
	drawSnake(ptrMySnake);

	do
	{
		drawFood();
		gotoxy(0, 23);
		fflush(stdout);
		usleep(100000);
	} while (advanceSnake(ptrMySnake));

	gotoxy(0, 24);
	printf("Exiting.\n");
	return 0;
}
